home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / parseaddr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-24  |  33.5 KB  |  1,630 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)parseaddr.c    5.13 (Berkeley) 6/1/90";
  23. static char  rcsid[] = "@(#)$Id: parseaddr.c,v 5.13.0.18 1991/06/25 04:47:05 paul Exp $";
  24. #endif /* not lint */
  25.  
  26. #include "sendmail.h"
  27.  
  28. #ifdef __STDC__
  29. # ifdef    CC_WONT_PROMOTE
  30. static int toktype(char);
  31. # else    /* !CC_WONT_PROMOTE */
  32. static int toktype(int);                /* char -> int */
  33. # endif    /* CC_WONT_PROMOTE */
  34. static void _rewrite(char **, int);
  35. static void callsubr(char **);
  36. static ADDRESS * buildaddr(char **, ADDRESS *);
  37. static void uurelativize(const char *, const char *, char **);
  38. #else /* !__STDC__ */
  39. static int toktype();
  40. static void _rewrite();
  41. static void callsubr();
  42. static ADDRESS * buildaddr();
  43. static void uurelativize();
  44. #endif /* __STDC__ */
  45.  
  46. char    *DelimChar;        /* set to point to the delimiter */
  47.  
  48. /*
  49. **  PARSEADDR -- Parse an address
  50. **
  51. **    Parses an address and breaks it up into three parts: a
  52. **    net to transmit the message on, the host to transmit it
  53. **    to, and a user on that host.  These are loaded into an
  54. **    ADDRESS header with the values squirreled away if necessary.
  55. **    The "user" part may not be a real user; the process may
  56. **    just reoccur on that machine.  For example, on a machine
  57. **    with an arpanet connection, the address
  58. **        csvax.bill@berkeley
  59. **    will break up to a "user" of 'csvax.bill' and a host
  60. **    of 'berkeley' -- to be transmitted over the arpanet.
  61. **
  62. **    Parameters:
  63. **        addr -- the address to parse.
  64. **        a -- a pointer to the address descriptor buffer.
  65. **            If NULL, a header will be created.
  66. **        copyf -- determines what shall be copied:
  67. **            -1 -- don't copy anything.  The printname
  68. **                (q_paddr) is just addr, and the
  69. **                user & host are allocated internally
  70. **                to parse.
  71. **            0 -- copy out the parsed user & host, but
  72. **                don't copy the printname.
  73. **            +1 -- copy everything.
  74. **        delim -- the character to terminate the address, passed
  75. **            to prescan.
  76. **
  77. **    Returns:
  78. **        A pointer to the address descriptor header (`a' if
  79. **            `a' is non-NULL).
  80. **        NULL on error.
  81. **
  82. **    Side Effects:
  83. **        none
  84. */
  85.  
  86. /* following delimiters are inherent to the internal algorithms */
  87. # define DELIMCHARS    "\001()<>,;\\\"\r\n"    /* word delimiters */
  88.  
  89. ADDRESS *
  90. parseaddr(addr, a, copyf, delim)
  91.     char *addr;
  92.     register ADDRESS *a;
  93.     int copyf;
  94.     char delim;
  95. {
  96.     register char **pvp;
  97.     register struct mailer *m;
  98.     char pvpbuf[PSBUFSIZE];
  99.  
  100.     /*
  101.     **  Initialize and prescan address.
  102.     */
  103.  
  104.     CurEnv->e_to = (char *)addr;
  105.     if (tTd(20, 1))
  106.         printf("\n--parseaddr(%s)\n", addr);
  107.  
  108.     if (invalidaddr(addr))
  109.         return (NULL);
  110.  
  111.     pvp = prescan(addr, delim, pvpbuf);
  112.     if (pvp == NULL)
  113.         return (NULL);
  114.  
  115.     /*
  116.     **  Apply rewriting rules.
  117.     **    Ruleset 0 does basic parsing.  It must resolve.
  118.     */
  119.  
  120.     rewrite(pvp, 3);
  121.     rewrite(pvp, 0);
  122.  
  123.     /*
  124.     **  See if we resolved to a real mailer.
  125.     */
  126.  
  127.     if (pvp[0][0] != CANONNET)
  128.     {
  129.         setstat(EX_USAGE);
  130.         usrerr("cannot resolve name");
  131.         return (NULL);
  132.     }
  133.  
  134.     /*
  135.     **  Build canonical address from pvp.
  136.     */
  137.  
  138.     a = buildaddr(pvp, a);
  139.     if (a == NULL)
  140.         return (NULL);
  141.     m = a->q_mailer;
  142.  
  143.     /*
  144.     **  Make local copies of the host & user and then
  145.     **  transport them out.
  146.     */
  147.  
  148.     if (copyf > 0)
  149.     {
  150.         char savec = *DelimChar;
  151.  
  152.         *DelimChar = '\0';
  153.         a->q_paddr = newstr(addr);
  154.         *DelimChar = savec;
  155.     }
  156.     else
  157.         a->q_paddr = addr;
  158.  
  159.     if (a->q_user == NULL)
  160.         a->q_user = "";
  161.     if (a->q_host == NULL)
  162.         a->q_host = "";
  163.  
  164.     if (copyf >= 0)
  165.     {
  166.         a->q_host = newstr(a->q_host);
  167.         if (a->q_user != a->q_paddr)
  168.             a->q_user = newstr(a->q_user);
  169.     }
  170.  
  171.     /*
  172.     **  Convert host name to lower case if requested.
  173.     **    User name will be done later.
  174.     */
  175.  
  176.     if (!bitnset(M_HST_UPPER, m->m_flags))
  177.         makelower(a->q_host);
  178.  
  179.     /*
  180.     **  Compute return value.
  181.     */
  182.  
  183.     if (tTd(20, 1))
  184.     {
  185.         printf("parseaddr-->");
  186.         printaddr(a, FALSE);
  187.     }
  188.  
  189.     return (a);
  190. }
  191. /*
  192. **  LOWERADDR -- map UPPER->lower case on addresses as requested.
  193. **
  194. **    Parameters:
  195. **        a -- address to be mapped.
  196. **
  197. **    Returns:
  198. **        none.
  199. **
  200. **    Side Effects:
  201. **        none.
  202. */
  203.  
  204. void
  205. loweraddr(a)
  206.     register ADDRESS *a;
  207. {
  208.     register MAILER *m = a->q_mailer;
  209.  
  210.     if (!bitnset(M_USR_UPPER, m->m_flags))
  211.         makelower(a->q_user);
  212. }
  213. /*
  214. **  INVALIDADDR -- check an address string for invalid control characters.
  215. **
  216. **    Parameters:
  217. **        addr -- address string to be checked.
  218. **
  219. **    Returns:
  220. **        TRUE if address string could cause problems, FALSE o/w.
  221. **
  222. **    Side Effects:
  223. **        ExitStat may be changed and an error message generated.
  224. */
  225.  
  226. bool
  227. invalidaddr(addr)
  228.     const char *addr;
  229. {
  230.     register const char *cp;
  231.     extern int errno;
  232.  
  233.     /* make sure error messages don't have garbage on them */
  234.     errno = 0;
  235.  
  236.     /*
  237.     ** Sendmail reserves characters 020 - 036 for rewriting rules
  238.     ** which can cause havoc (e.g. infinite rewriting loops) if
  239.     ** one shows up at the wrong time.  If any of these characters
  240.     ** appear in an address, the address is deemed "invalid" and
  241.     ** an error message is generated.
  242.     */
  243.  
  244.     for (cp = addr; *cp; cp++)
  245.         if ((*cp >= MATCHZANY && *cp <= HOSTEND) || *cp == '\001')
  246.         {
  247.             setstat(EX_USAGE);
  248.             usrerr("address contained invalid control char(s)");
  249.             return (TRUE);
  250.         }
  251.     return (FALSE);
  252. }
  253. /*
  254. **  PRESCAN -- Prescan name and make it canonical
  255. **
  256. **    Scans a name and turns it into a set of tokens.  This process
  257. **    deletes blanks and comments (in parentheses).
  258. **
  259. **    This routine knows about quoted strings and angle brackets.
  260. **
  261. **    There are certain subtleties to this routine.  The one that
  262. **    comes to mind now is that backslashes on the ends of names
  263. **    are silently stripped off; this is intentional.  The problem
  264. **    is that some versions of sndmsg (like at LBL) set the kill
  265. **    character to something other than @ when reading addresses;
  266. **    so people type "csvax.eric\@berkeley" -- which screws up the
  267. **    berknet mailer.
  268. **
  269. **    Parameters:
  270. **        addr -- the name to chomp.
  271. **        delim -- the delimiter for the address, normally
  272. **            '\0' or ','; \0 is accepted in any case.
  273. **            If '\t' then we are reading the .cf file.
  274. **        pvpbuf -- place to put the saved text -- note that
  275. **            the pointers are static.
  276. **
  277. **    Returns:
  278. **        A pointer to a vector of tokens.
  279. **        NULL on error.
  280. **
  281. **    Side Effects:
  282. **        sets DelimChar to point to the character matching 'delim'.
  283. */
  284.  
  285. /* states and character types */
  286. # define OPR        0    /* operator */
  287. # define ATM        1    /* atom */
  288. # define QST        2    /* in quoted string */
  289. # define SPC        3    /* chewing up spaces */
  290. # define ONE        4    /* pick up one character */
  291.  
  292. # define NSTATES    5    /* number of states */
  293. # define TYPE        017    /* mask to select state type */
  294.  
  295. /* meta bits for table */
  296. # define M        020    /* meta character; don't pass through */
  297. # define B        040    /* cause a break */
  298. # define MB        M|B    /* meta-break */
  299.  
  300. static short StateTab[NSTATES][NSTATES] =
  301. {
  302.    /*    oldst    chtype>    OPR    ATM    QST    SPC    ONE    */
  303.     /*OPR*/        OPR|B,    ATM|B,    QST|B,    SPC|MB,    ONE|B,
  304.     /*ATM*/        OPR|B,    ATM,    QST|B,    SPC|MB,    ONE|B,
  305.     /*QST*/        QST,    QST,    OPR,    QST,    QST,
  306.     /*SPC*/        OPR,    ATM,    QST,    SPC|M,    ONE,
  307.     /*ONE*/        OPR,    OPR,    OPR,    OPR,    OPR,
  308. };
  309.  
  310. # define NOCHAR        -1    /* signal nothing in lookahead token */
  311.  
  312. char **
  313. prescan(addr, delim, pvpbuf)
  314.     char *addr;
  315.     char delim;
  316.     char pvpbuf[];
  317. {
  318.     register char *p;
  319.     register char *q;
  320.     register int c;
  321.     char **avp;
  322.     bool bslashmode;
  323.     int cmntcnt;
  324.     int anglecnt;
  325.     char *tok;
  326.     int state;
  327.     int newstate;
  328.     static char *av[MAXATOM+1];
  329.     extern int errno;
  330.  
  331.     /* make sure error messages don't have garbage on them */
  332.     errno = 0;
  333.  
  334.     q = pvpbuf;
  335.     bslashmode = FALSE;
  336.     cmntcnt = 0;
  337.     anglecnt = 0;
  338.     avp = av;
  339.     state = OPR;
  340.     c = NOCHAR;
  341.     p = addr;
  342.     if (tTd(22, 45))
  343.     {
  344.         printf("prescan: ");
  345.         xputs(p);
  346.         (void) putchar('\n');
  347.     }
  348.  
  349.     do
  350.     {
  351.         /* read a token */
  352.         tok = q;
  353.         for (;;)
  354.         {
  355.             /* store away any old lookahead character */
  356.             if (c != NOCHAR)
  357.             {
  358.                 /* see if there is room */
  359.                 if (q >= &pvpbuf[PSBUFSIZE - 5])
  360.                 {
  361.                     usrerr("Address too long");
  362.                     DelimChar = p;
  363.                     return (NULL);
  364.                 }
  365.  
  366.                 /* squirrel it away */
  367.                 *q++ = c;
  368.             }
  369.  
  370.             /* read a new input character */
  371.             c = *p++;
  372.             if (c == '\0')
  373.                 break;
  374.             c &= ~0200;
  375.  
  376.             if (tTd(22, 101))
  377.                 printf("c=%c, s=%d; ", c, state);
  378.  
  379.             /* chew up special characters */
  380.             *q = '\0';
  381.             if (bslashmode)
  382.             {
  383.                 /* kludge \! for naive users */
  384.                 if (c != '!')
  385.                     c |= 0200;
  386.                 bslashmode = FALSE;
  387.             }
  388.             else if (c == '\\')
  389.             {
  390.                 bslashmode = TRUE;
  391.                 c = NOCHAR;
  392.             }
  393.             if (state == QST)
  394.             {
  395.                 /* do nothing, just avoid next clauses */
  396.             }
  397.             else if (c == '(')
  398.             {
  399.                 cmntcnt++;
  400.                 c = NOCHAR;
  401.             }
  402.             else if (c == ')')
  403.             {
  404.                 if (cmntcnt <= 0)
  405.                 {
  406.                     usrerr("Unbalanced ')'");
  407.                     DelimChar = p;
  408.                     return (NULL);
  409.                 }
  410.                 else
  411.                     cmntcnt--;
  412.             }
  413.             else if (cmntcnt > 0)
  414.                 c = NOCHAR;
  415.             else if (c == '<')
  416.                 anglecnt++;
  417.             else if (c == '>')
  418.             {
  419.                 if (anglecnt <= 0)
  420.                 {
  421.                     usrerr("Unbalanced '>'");
  422.                     DelimChar = p;
  423.                     return (NULL);
  424.                 }
  425.                 anglecnt--;
  426.             }
  427.             else if (delim == ' ' && isspace(c))
  428.                 c = ' ';
  429.  
  430.             if (c == ';') /* semicolons are not tokens */
  431.                 c = NOCHAR;
  432.  
  433.             if (c == NOCHAR)
  434.                 continue;
  435.  
  436.             /* see if this is end of input */
  437.             if (c == delim && anglecnt <= 0 && state != QST)
  438.                 break;
  439.  
  440.             newstate = StateTab[state][toktype(c)];
  441.             if (tTd(22, 101))
  442.                 printf("ns=%02o\n", newstate);
  443.             state = newstate & TYPE;
  444.             if (bitset(M, newstate))
  445.                 c = NOCHAR;
  446.             if (bitset(B, newstate))
  447.                 break;
  448.         }
  449.  
  450.         /* new token */
  451.         if (tok != q)
  452.         {
  453.             *q++ = '\0';
  454.             if (tTd(22, 36))
  455.             {
  456.                 printf("tok=");
  457.                 xputs(tok);
  458.                 (void) putchar('\n');
  459.             }
  460.             if (avp >= &av[MAXATOM])
  461.             {
  462.                 syserr("prescan: too many tokens");
  463.                 DelimChar = p;
  464.                 return (NULL);
  465.             }
  466.             *avp++ = tok;
  467.         }
  468.     } while (c != '\0' && (c != delim || anglecnt > 0));
  469.     *avp = NULL;
  470.     DelimChar = --p;
  471.     if (cmntcnt > 0)
  472.         usrerr("Unbalanced '('");
  473.     else if (anglecnt > 0)
  474.         usrerr("Unbalanced '<'");
  475.     else if (state == QST)
  476.         usrerr("Unbalanced '\"'");
  477.     else if (av[0] != NULL)
  478.         return (av);
  479.     return (NULL);
  480. }
  481. /*
  482. **  TOKTYPE -- return token type
  483. **
  484. **    Parameters:
  485. **        c -- the character in question.
  486. **
  487. **    Returns:
  488. **        Its type.
  489. **
  490. **    Side Effects:
  491. **        none.
  492. */
  493.  
  494. static int
  495. toktype(c)
  496.     register char c;
  497. {
  498.     static char buf[50];
  499.     static bool firstime = TRUE;
  500.  
  501.     if (firstime)
  502.     {
  503.         firstime = FALSE;
  504.         expand("\001o", buf, &buf[sizeof buf - 1], CurEnv);
  505.         (void) strcat(buf, DELIMCHARS);
  506.     }
  507.     if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS ||
  508.         c == MATCHMAP   || c == MATCHNMAP)
  509.         return (ONE);
  510. #ifdef MACVALUE
  511.     if (c == MACVALUE)
  512.         return (ONE);
  513. #endif /* MACVALUE */
  514.     if (c == '"')
  515.         return (QST);
  516.     if (!isascii(c))
  517.         return (ATM);
  518.     if (isspace(c) || c == ')')
  519.         return (SPC);
  520.     if (iscntrl(c) || index(buf, c) != NULL)
  521.         return (OPR);
  522.     return (ATM);
  523. }
  524. /*
  525. **  REWRITE -- apply rewrite rules to token vector.
  526. **
  527. **    This routine is an ordered production system.  Each rewrite
  528. **    rule has a LHS (called the pattern) and a RHS (called the
  529. **    rewrite); 'rwr' points the the current rewrite rule.
  530. **
  531. **    For each rewrite rule, 'avp' points the address vector we
  532. **    are trying to match against, and 'pvp' points to the pattern.
  533. **    If pvp points to a special match value (MATCHZANY, MATCHANY,
  534. **    MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
  535. **    matched is saved away in the match vector (pointed to by 'mvp').
  536. **
  537. **    When a match between avp & pvp does not match, we try to
  538. **    back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
  539. **    we must also back out the match in mvp.  If we reach a
  540. **    MATCHANY or MATCHZANY we just extend the match and start
  541. **    over again.
  542. **
  543. **    When we finally match, we rewrite the address vector
  544. **    and try over again.
  545. **
  546. **    Parameters:
  547. **        pvp -- pointer to token vector.
  548. **
  549. **    Returns:
  550. **        none.
  551. **
  552. **    Side Effects:
  553. **        pvp is modified.
  554. */
  555.  
  556. struct match
  557. {
  558.     char    **first;    /* first token matched */
  559.     char    **last;        /* last token matched */
  560. };
  561.  
  562. # define MAXMATCH    9    /* max params per rewrite */
  563.  
  564. static int nrw;
  565.  
  566. void
  567. rewrite(pvp, ruleset)
  568.     char **pvp;
  569.     int ruleset;
  570. {
  571.     nrw = 0;
  572.     _rewrite(pvp, ruleset);
  573. }
  574.  
  575. static void
  576. _rewrite(pvp, ruleset)
  577.     char **pvp;
  578.     int ruleset;
  579. {
  580.     register char *ap;        /* address pointer */
  581.     register char *rp;        /* rewrite pointer */
  582.     register char **avp;        /* address vector pointer */
  583.     register char **rvp;        /* rewrite vector pointer */
  584.     register struct match *mlp;    /* cur ptr into mlist */
  585.     register struct rewrite *rwr;    /* pointer to current rewrite rule */
  586.     struct match mlist[MAXMATCH];    /* stores match on LHS */
  587.     char *npvp[MAXATOM+1];        /* temporary space for rebuild */
  588.     char tokbuf[MAXNAME+1];        /* for concatenated class tokens */
  589.      int nloops, nmatches = 0;    /* for looping rule checks */
  590.  
  591.     if (OpMode == MD_TEST || tTd(21, 2))
  592.     {
  593.         printf("rewrite: ruleset %2d   input:", ruleset);
  594.         printcav(pvp);
  595.     }
  596.     if (pvp == NULL)
  597.         return;
  598.  
  599.     if (++nrw > 100)
  600.     {
  601.         char buf[MAXLINE];
  602.  
  603.         buf[0] = buf[MAXLINE-1] = 0;
  604.         while (*pvp)
  605.             (void) strncat(buf, *pvp++, sizeof buf);
  606.         syserr("address causes rewrite loop: <%s>", buf);
  607.         return;
  608.     }
  609.  
  610.     /*
  611.     **  Run through the list of rewrite rules, applying
  612.     **    any that match.
  613.     */
  614.  
  615.     for (rwr = RewriteRules[ruleset]; rwr != NULL; )
  616.     {
  617.         if (tTd(21, 12))
  618.         {
  619.             printf("-----trying rule:");
  620.             printcav(rwr->r_lhs);
  621.         }
  622.  
  623.         /* try to match on this rule */
  624.         mlp = mlist;
  625.         rvp = rwr->r_lhs;
  626.         avp = pvp;
  627.         nloops = 0;
  628.         while ((ap = *avp) != NULL || *rvp != NULL)
  629.         {
  630.             if (nloops++ > 200)
  631.             {
  632.                 syserr("Looping on ruleset %d, rule %d",
  633.                     ruleset, rwr-RewriteRules[ruleset]);
  634.                 break;
  635.             }
  636.             rp = *rvp;
  637.             if (tTd(21, 35))
  638.             {
  639.                 printf("ap=");
  640.                 xputs(ap);
  641.                 printf(", rp=");
  642.                 xputs(rp);
  643.                 printf("\n");
  644.             }
  645.             if (rp == NULL)
  646.             {
  647.                 /* end-of-pattern before end-of-address */
  648.                 goto backup;
  649.             }
  650.             if (ap == NULL && *rp != MATCHZANY)
  651.             {
  652.                 /* end-of-input */
  653.                 break;
  654.             }
  655.  
  656.             switch (*rp)
  657.             {
  658.                 register STAB *s;
  659.                 char **oldavp;
  660.  
  661.               case MATCHNCLASS:
  662.                 /* match any single token not in a class */
  663.                 s = stab(ap, ST_CLASS, ST_FIND);
  664.                 if (s != NULL && bitnset(rp[1], s->s_class))
  665.                         goto backup;
  666.  
  667.                 /* match exactly one token */
  668.                 mlp->first = avp;
  669.                 mlp->last = avp++;
  670.                 mlp++;
  671.                 break;
  672.  
  673.               case MATCHCLASS:
  674.                 /* match any token in a class */
  675.                 /* slow, concat version by lel@ida.liu.se */
  676.                 /* handles multi-token class matches, though */
  677.                 oldavp = avp;
  678.                 *tokbuf = (char) NULL;
  679.                 do {
  680.                     if (*avp == NULL)
  681.                     {
  682.                         avp = oldavp;
  683.                         goto backup;
  684.                     }
  685.                     (void) strcat(tokbuf, *avp++);
  686.                     s = stab(tokbuf, ST_CLASS, ST_FIND);
  687.                 } while (s == NULL || !bitnset(rp[1], s->s_class));
  688.  
  689.                 mlp->first = oldavp;
  690.                 mlp->last = avp-1;
  691.                 mlp++;
  692.                 break;
  693.  
  694.               case MATCHMAP:
  695.                 /* match any token in a DBM map */
  696.                 /* handles multi-token class matches */
  697.                 oldavp = avp;
  698.                 *tokbuf = (char) NULL;
  699.                 do {
  700.                     if (*avp == NULL)
  701.                     {
  702.                         avp = oldavp;
  703.                         goto backup;
  704.                     }
  705.                     (void) strcat(tokbuf, *avp++);
  706.                 } while (mapkey(rp[1], tokbuf, sizeof(tokbuf)-1,                            NULL) == NULL);
  707.                 mlp->first = oldavp;
  708.                 mlp->last = avp-1;
  709.                 mlp++;
  710.                 break;
  711.  
  712.               case MATCHNMAP:
  713.                 /* match any token not in a DBM map */
  714.                 if ((rp = mapkey(rp[1], ap, 0, NULL)) != NULL)
  715.                 {
  716.                     free(rp);
  717.                     goto backup;
  718.                 }
  719.  
  720.                 /* match exactly one token */
  721.                 mlp->first = avp;
  722.                 mlp->last = avp++;
  723.                 mlp++;
  724.                 break;
  725.  
  726.               case MATCHONE:
  727.               case MATCHANY:
  728.                 /* match exactly one token */
  729.                 mlp->first = avp;
  730.                 mlp->last = avp++;
  731.                 mlp++;
  732.                 break;
  733.  
  734.               case MATCHZANY:
  735.                 /* match zero or more tokens */
  736.                 mlp->first = avp;
  737.                 mlp->last = avp - 1;
  738.                 mlp++;
  739.                 break;
  740.  
  741. #ifdef MACVALUE
  742.               case MACVALUE:
  743.                 {
  744.                 char *p = macvalue(rp[1], CurEnv);
  745.  
  746.                 if (tTd(21, 2))
  747.                     printf("expanding runtime macro '%c' to \"%s\"\n",
  748.                         rp[1], p ? p : "(null)");
  749.                 oldavp = avp;
  750.                 if (p) while (*p)
  751.                 {
  752.                     if (*avp == NULL ||
  753.                        strncasecmp(p,*avp,strlen(*avp)))
  754.                     {
  755.                         avp = oldavp;
  756.                         goto backup;
  757.                     }
  758.                     p += strlen(*avp++);
  759.                 }
  760.                 mlp->first = oldavp;
  761.                 mlp->last = avp -1;
  762.                 }
  763.             mlp++;
  764.             break;
  765. #endif /* MACVALUE */
  766.  
  767.               default:
  768.                 /* must have exact match */
  769.                 if (strcasecmp(rp, ap))
  770.                     goto backup;
  771.                 avp++;
  772.                 break;
  773.             }
  774.  
  775.             /* successful match on this token */
  776.             rvp++;
  777.             continue;
  778.  
  779.           backup:
  780.             /* match failed -- back up */
  781.             while (--rvp >= rwr->r_lhs)
  782.             {
  783.                 rp = *rvp;
  784.                 if (*rp == MATCHCLASS)
  785.                 {
  786.                     register STAB *s;
  787.                     char **oldavp;
  788.  
  789.                     /* attempt to extend binding */
  790.                     /* slow, concat version by lel@ida.liu.se */
  791.  
  792.                     oldavp = avp;
  793.                     *tokbuf = (char) NULL;
  794.                     for (avp = mlp[-1].first;
  795.                         avp <= mlp[-1].last; avp++)
  796.                         (void) strcat(tokbuf, *avp);
  797.  
  798.                     do {
  799.                         if (*avp == NULL)
  800.                         {
  801.                             /* back out binding */
  802.                             avp = oldavp;
  803.                             mlp--;
  804.                             goto cantextend;
  805.                         }
  806.                         (void) strcat(tokbuf, *avp++);
  807.                         s = stab(tokbuf, ST_CLASS, ST_FIND);
  808.                     } while (s == NULL ||
  809.                         !bitnset(rp[1], s->s_class));
  810.  
  811.                     /* found an extension */
  812.                     mlp[-1].last = avp-1;
  813.                     rvp++;
  814.                     break;
  815.                 }
  816. cantextend:
  817.                 if (*rp == MATCHANY || *rp == MATCHZANY)
  818.                 {
  819.                     /* extend binding and continue */
  820.                     avp = ++mlp[-1].last;
  821.                     avp++;
  822.                     rvp++;
  823.                     break;
  824.                 }
  825.                 avp--;
  826.                 if (*rp == MATCHONE || *rp == MATCHNCLASS)
  827.                 {
  828.                     /* back out binding */
  829.                     mlp--;
  830.                 }
  831.             }
  832.  
  833.             if (rvp < rwr->r_lhs)
  834.             {
  835.                 /* total failure to match */
  836.                 break;
  837.             }
  838.         }
  839.  
  840.         /*
  841.         **  See if we successfully matched
  842.         */
  843.  
  844.         if (rvp < rwr->r_lhs || *rvp != NULL)
  845.         {
  846.             if (tTd(21, 10))
  847.                 printf("----- rule fails\n");
  848.             rwr = rwr->r_next;
  849.             nmatches = 0;
  850.             continue;
  851.         }
  852.  
  853.         if (nmatches++ > 200)
  854.         {
  855.             syserr("Loop in ruleset %d, rule %d (too many matches)",
  856.                 ruleset, rwr-RewriteRules[ruleset]);
  857.             rwr = rwr->r_next;
  858.             nmatches = 0;
  859.             continue;
  860.         }
  861.  
  862.         rvp = rwr->r_rhs;
  863.         if (tTd(21, 12))
  864.         {
  865.             printf("-----rule matches:");
  866.             printcav(rvp);
  867.         }
  868.  
  869.         rp = *rvp;
  870.         if (*rp == CANONUSER)
  871.         {
  872.             rvp++;
  873.             rwr = rwr->r_next;
  874.             nmatches = 0;
  875.         }
  876.         else if (*rp == CANONHOST)
  877.         {
  878.             rvp++;
  879.             rwr = NULL;
  880.         }
  881.         else if (*rp == CANONNET)
  882.             rwr = NULL;
  883.  
  884.         /* substitute */
  885.         for (avp = npvp; *rvp != NULL; rvp++)
  886.         {
  887.             register struct match *m;
  888.             register char **pp;
  889.  
  890.             rp = *rvp;
  891.             if (*rp == MATCHREPL)
  892.             {
  893.                 /* substitute from LHS */
  894.                 m = &mlist[rp[1] - '1'];
  895.                 if (m >= mlp)
  896.                 {
  897.                     syserr("rewrite: ruleset %d: replacement #%c out of bounds",
  898.                         ruleset, rp[1]);
  899.                     return;
  900.                 }
  901.                 if (tTd(21, 15))
  902.                 {
  903.                     printf("$%c:", rp[1]);
  904.                     pp = m->first;
  905.                     while (pp <= m->last)
  906.                     {
  907.                         printf(" %x=\"", *pp);
  908.                         (void) fflush(stdout);
  909.                         printf("%s\"", *pp++);
  910.                     }
  911.                     printf("\n");
  912.                 }
  913.                 pp = m->first;
  914.                 while (pp <= m->last)
  915.                 {
  916.                     if (avp >= &npvp[MAXATOM])
  917.                     {
  918.                         syserr("rewrite: expansion too long");
  919.                         return;
  920.                     }
  921.                     *avp++ = *pp++;
  922.                 }
  923.             }
  924.             else
  925.             {
  926.                 /* vanilla replacement */
  927.                 if (avp >= &npvp[MAXATOM])
  928.                 {
  929.     toolong:
  930.                     syserr("rewrite: expansion too long");
  931.                     return;
  932.                 }
  933. #ifdef MACVALUE
  934.                 if (*rp == MACVALUE)
  935.                 {
  936.                     char *p = macvalue(rp[1], CurEnv);
  937.  
  938.                     if (tTd(21, 2))
  939.                         printf("expanding runtime macro '%c' to \"%s\"\n",
  940.                             rp[1], p ? p : "(null)");
  941.                     if (p)
  942.                         *avp++ = p;
  943.                 }
  944.                 else
  945. #endif /* MACVALUE */
  946.                     *avp++ = rp;
  947.             }
  948.         }
  949.         *avp++ = NULL;
  950.  
  951.         /*
  952.         **  Check for any hostname lookups.
  953.         */
  954.  
  955.         for (rvp = npvp; *rvp != NULL; rvp++)
  956.         {
  957.             char **hbrvp, **ubrvp;
  958.             char **xpvp;
  959.             int trsize;
  960.             char *olddelimchar;
  961.             char hbuf[MAXNAME + 1], ubuf[MAXNAME + 1];
  962.             char *pvpb1[MAXATOM + 1];
  963.             char pvpbuf[PSBUFSIZE];
  964.             bool match, defaultpart;
  965.             char begintype;
  966.             char db = '\0';
  967.  
  968.             if (**rvp != HOSTBEGIN && **rvp != KEYBEGIN)
  969.                 continue;
  970.  
  971.             /*
  972.             **  Got a hostname or database lookup.
  973.             **
  974.             **    This could be optimized fairly easily.
  975.             */
  976.  
  977.             begintype = **rvp;
  978.             hbrvp = rvp;
  979.             ubrvp = NULL;
  980.  
  981.             /* read database name if that's what we're up for */
  982.             if (begintype == KEYBEGIN)
  983.             {
  984.                 if (*++rvp != NULL)
  985.                     db = **rvp;
  986.             }
  987.  
  988.             /* extract the match part */
  989.             if (begintype == HOSTBEGIN)
  990.                 while (*++rvp != NULL && **rvp != HOSTEND &&
  991.                    **rvp != CANONUSER)
  992.                 continue;
  993.             else
  994.                 while (*++rvp != NULL && **rvp != KEYEND &&
  995.                    **rvp != CANONHOST && **rvp != CANONUSER)
  996.                     continue;
  997.             /* got a sprintf argument? */
  998.             if (**rvp == CANONHOST)
  999.             {
  1000.                 *rvp = NULL;
  1001.                 ubrvp = rvp+1;
  1002.                 while (*++rvp != NULL && **rvp != KEYEND &&
  1003.                     **rvp != CANONUSER)
  1004.                     continue;
  1005.             }
  1006.             defaultpart = **rvp == CANONUSER;
  1007.             if (*rvp != NULL)
  1008.                 *rvp++ = NULL;
  1009.  
  1010.             /* save the remainder of the input string */
  1011.             trsize = (int) (avp - rvp + 1) * sizeof *rvp;
  1012.             bcopy((char *) rvp, (char *) pvpb1, trsize);
  1013.  
  1014.             /* Look it up (lowercase version) */
  1015.             cataddr(hbrvp + (begintype == HOSTBEGIN ? 1 : 2),
  1016.                 hbuf, sizeof hbuf);
  1017.             if (begintype == HOSTBEGIN)
  1018. #ifdef VMUNIX
  1019.                 match = maphostname(hbuf, sizeof hbuf);
  1020. #else /* !VMUNIX */
  1021.                 match = FALSE;
  1022. #endif /* VMUNIX */
  1023.             else
  1024.             {
  1025.                 if (ubrvp == NULL)
  1026.                 {
  1027.                     /* no sprintf argument part */
  1028.                     match = (mapkey(db, hbuf, sizeof hbuf, NULL) != NULL);
  1029.                 }
  1030.                 else
  1031.                 {
  1032.                     cataddr(ubrvp, ubuf, sizeof ubuf);
  1033.                     match = (mapkey(db, hbuf, sizeof hbuf, ubuf) != NULL);
  1034.                 }
  1035.             }
  1036.             if (match || !defaultpart)
  1037.             {
  1038.                 /* scan the new route/host name */
  1039.             olddelimchar = DelimChar;
  1040.                 xpvp = prescan(hbuf, '\0', pvpbuf);
  1041.             DelimChar = olddelimchar;
  1042.                 if (xpvp == NULL)
  1043.                 {
  1044.                     syserr("rewrite: cannot prescan %s: %s", 
  1045.                         begintype == HOSTBEGIN ?
  1046.                         "new hostname" :
  1047.                         "dbm lookup result",
  1048.                         hbuf);
  1049.                 return;
  1050.             }
  1051.  
  1052.             /* append it to the token list */
  1053.                 for (avp = hbrvp; *xpvp != NULL; xpvp++)
  1054.                 {
  1055.                 *avp++ = newstr(*xpvp);
  1056.                 if (avp >= &npvp[MAXATOM])
  1057.                     goto toolong;
  1058.                 }
  1059.             }
  1060.             else
  1061.                 avp = hbrvp;
  1062.  
  1063.             /* restore the old trailing information */
  1064.             rvp = avp - 1;
  1065.             for (xpvp = pvpb1; *xpvp != NULL; xpvp++)
  1066.             {
  1067.                 if (defaultpart && (begintype == HOSTBEGIN ?
  1068.                     **xpvp == HOSTEND :
  1069.                     **xpvp == KEYEND))
  1070.                 {
  1071.                     defaultpart = FALSE;
  1072.                     rvp = avp - 1;
  1073.                 }
  1074.                 else if (!defaultpart || !match)
  1075.                     *avp++ = *xpvp;
  1076.                 if (avp >= &npvp[MAXATOM])
  1077.                     goto toolong;
  1078.             }
  1079.             *avp++ = NULL;
  1080.  
  1081.             /*break;*/
  1082.         }
  1083.  
  1084.         /*
  1085.         **  Check for subroutine calls.
  1086.         **  Then copy vector back into original space.
  1087.         */
  1088.  
  1089.         callsubr(npvp);
  1090.  
  1091.         for (avp = npvp; *avp++ != NULL;);
  1092.             bcopy((char *) npvp, (char *) pvp,
  1093.                 (int) (avp - npvp) * sizeof *avp);
  1094.  
  1095.         if (tTd(21, 4))
  1096.         {
  1097.             printf("rewritten as:");
  1098.             printcav(pvp);
  1099.         }
  1100.     }
  1101.  
  1102.     if (OpMode == MD_TEST || tTd(21, 2))
  1103.     {
  1104.         printf("rewrite: ruleset %2d returns:", ruleset);
  1105.         printcav(pvp);
  1106.     }
  1107. }
  1108. /*
  1109. **  CALLSUBR -- call subroutines in rewrite vector
  1110. **
  1111. **    Parameters:
  1112. **        pvp -- pointer to token vector.
  1113. **
  1114. **    Returns:
  1115. **        none.
  1116. **
  1117. **    Side Effects:
  1118. **        pvp is modified.
  1119. */
  1120.  
  1121. static void
  1122. callsubr(pvp)
  1123.     char **pvp;
  1124. {
  1125.     char **rvp;
  1126.     int subr;
  1127.  
  1128.     for (; *pvp != NULL; pvp++)
  1129.         if (**pvp == CALLSUBR)
  1130.         {
  1131.             subr = atoi(pvp[1]);
  1132.  
  1133.             if (tTd(21, 3))
  1134.                 printf("-----callsubr %d\n", subr);
  1135.  
  1136.             /*
  1137.             **  Take care of possible inner calls.
  1138.             */
  1139.             callsubr(pvp+2);
  1140.  
  1141.             /*
  1142.             **  Move vector up over calling opcode.
  1143.             */
  1144.             for (rvp = pvp+2; *rvp != NULL; rvp++)
  1145.                 rvp[-2] = rvp[0];
  1146.             rvp[-2] = NULL;
  1147.  
  1148.             /*
  1149.             **  Call inferior ruleset.
  1150.             */
  1151.             rewrite(pvp, subr);
  1152.  
  1153.             break;
  1154.         }
  1155. }
  1156. /*
  1157. **  BUILDADDR -- build address from token vector.
  1158. **
  1159. **    Parameters:
  1160. **        tv -- token vector.
  1161. **        a -- pointer to address descriptor to fill.
  1162. **            If NULL, one will be allocated.
  1163. **
  1164. **    Returns:
  1165. **        NULL if there was an error.
  1166. **        'a' otherwise.
  1167. **
  1168. **    Side Effects:
  1169. **        fills in 'a'
  1170. */
  1171.  
  1172. static ADDRESS *
  1173. buildaddr(tv, a)
  1174.     register char **tv;
  1175.     register ADDRESS *a;
  1176. {
  1177.     static char buf[MAXNAME];
  1178.     struct mailer **mp;
  1179.     register struct mailer *m;
  1180.  
  1181.     if (a == NULL)
  1182.         a = (ADDRESS *) xalloc(sizeof *a);
  1183.     bzero((char *) a, sizeof *a);
  1184.  
  1185.     /* figure out what net/mailer to use */
  1186.     if (**tv != CANONNET)
  1187.     {
  1188.         syserr("buildaddr: no net");
  1189.         return (NULL);
  1190.     }
  1191.     tv++;
  1192.     if (!strcasecmp(*tv, "error"))
  1193.     {
  1194.         if (**++tv == CANONHOST)
  1195.         {
  1196.             setstat(atoi(*++tv));
  1197.             tv++;
  1198.         }
  1199.         buf[0] = '\0';
  1200.         for (; (*tv != NULL) && (**tv != CANONUSER); tv++)
  1201.         {
  1202.             if (buf[0] != '\0')
  1203.                 (void) strcat(buf, " ");
  1204.             (void) strcat(buf, *tv);
  1205.         }
  1206.         if (**tv != CANONUSER)
  1207.             syserr("buildaddr: error: no user");
  1208.         while (*++tv != NULL)
  1209.         {
  1210.             if (buf[0] != '\0')
  1211.                 (void) strcat(buf, " ");
  1212.             (void) strcat(buf, *tv);
  1213.         }
  1214.         usrerr(buf);
  1215.         return (NULL);
  1216.     }
  1217.     for (mp = Mailer; (m = *mp++) != NULL; )
  1218.     {
  1219.         if (!strcasecmp(m->m_name, *tv))
  1220.             break;
  1221.     }
  1222.     if (m == NULL)
  1223.     {
  1224.         syserr("buildaddr: unknown mailer %s", *tv);
  1225.         return (NULL);
  1226.     }
  1227.     a->q_mailer = m;
  1228.  
  1229.     /* figure out what host (if any) */
  1230.     if (**++tv != CANONHOST)
  1231.     {
  1232.         if (!bitnset(M_LOCAL, m->m_flags))
  1233.         {
  1234.             syserr("buildaddr: no host");
  1235.             return (NULL);
  1236.         }
  1237.         else
  1238.             a->q_host = NULL;
  1239.     }
  1240.     else
  1241.     {
  1242.         buf[0] = '\0';
  1243.         while (*++tv != NULL && **tv != CANONUSER)
  1244.             (void) strcat(buf, *tv);
  1245.         a->q_host = newstr(buf);
  1246.     }
  1247.  
  1248.     /* figure out the user */
  1249.     if (*tv == NULL || **tv != CANONUSER)
  1250.     {
  1251.         syserr("buildaddr: no user");
  1252.         return (NULL);
  1253.     }
  1254.  
  1255.     /* define tohost before running mailer rulesets */
  1256.     define('h', a->q_host, CurEnv);
  1257.  
  1258.     /* rewrite according recipient mailer rewriting rules */
  1259.     rewrite(++tv, 2);
  1260.     if (m->m_re_rwset > 0)
  1261.         rewrite(tv, m->m_re_rwset);
  1262.     rewrite(tv, 4);
  1263.  
  1264.     /* save the result for the command line/RCPT argument */
  1265.     cataddr(tv, buf, sizeof buf);
  1266.     a->q_user = buf;
  1267.  
  1268.     return (a);
  1269. }
  1270. /*
  1271. **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
  1272. **
  1273. **    Parameters:
  1274. **        pvp -- parameter vector to rebuild.
  1275. **        buf -- buffer to build the string into.
  1276. **        sz -- size of buf.
  1277. **
  1278. **    Returns:
  1279. **        none.
  1280. **
  1281. **    Side Effects:
  1282. **        Destroys buf.
  1283. */
  1284.  
  1285. void
  1286. cataddr(pvp, buf, sz)
  1287.     char **pvp;
  1288.     char *buf;
  1289.     register int sz;
  1290. {
  1291.     bool oatomtok = FALSE;
  1292.     bool natomtok;
  1293.     register int i;
  1294.     register char *p;
  1295.  
  1296.     if (pvp == NULL)
  1297.     {
  1298.         (void) strcpy(buf, "");
  1299.         return;
  1300.     }
  1301.     p = buf;
  1302.     sz -= 2;
  1303.     while (*pvp != NULL && (i = strlen(*pvp)) < sz)
  1304.     {
  1305.         natomtok = (toktype(**pvp) == ATM);
  1306.         if (oatomtok && natomtok)
  1307.             *p++ = SpaceSub;
  1308.         (void) strcpy(p, *pvp);
  1309.         oatomtok = natomtok;
  1310.         p += i;
  1311.         sz -= i + 1;
  1312.         pvp++;
  1313.     }
  1314.     *p = '\0';
  1315. }
  1316. /*
  1317. **  SAMEADDR -- Determine if two addresses are the same
  1318. **
  1319. **    This is not just a straight comparison -- if the mailer doesn't
  1320. **    care about the host we just ignore it, etc.
  1321. **
  1322. **    Parameters:
  1323. **        a, b -- pointers to the internal forms to compare.
  1324. **
  1325. **    Returns:
  1326. **        TRUE -- they represent the same mailbox.
  1327. **        FALSE -- they don't.
  1328. **
  1329. **    Side Effects:
  1330. **        none.
  1331. */
  1332.  
  1333. bool
  1334. sameaddr(a, b)
  1335.     register ADDRESS *a;
  1336.     register ADDRESS *b;
  1337. {
  1338.     /* if they don't have the same mailer, forget it */
  1339.     if (a->q_mailer != b->q_mailer)
  1340.         return (FALSE);
  1341.  
  1342.     /* if the user isn't the same, we can drop out */
  1343.     if (strcasecmp(a->q_user, b->q_user))
  1344.         return (FALSE);
  1345.  
  1346.     /* if the mailer ignores hosts, we have succeeded! */
  1347.     if (bitnset(M_LOCAL, a->q_mailer->m_flags))
  1348.         return (TRUE);
  1349.  
  1350.     /* otherwise compare hosts (but be careful for NULL ptrs) */
  1351.     if (a->q_host == NULL || b->q_host == NULL)
  1352.         return (FALSE);
  1353.     if (strcasecmp(a->q_host, b->q_host))
  1354.         return (FALSE);
  1355.  
  1356.     return (TRUE);
  1357. }
  1358. /*
  1359. **  PRINTADDR -- print address (for debugging)
  1360. **
  1361. **    Parameters:
  1362. **        a -- the address to print
  1363. **        follow -- follow the q_next chain.
  1364. **
  1365. **    Returns:
  1366. **        none.
  1367. **
  1368. **    Side Effects:
  1369. **        none.
  1370. */
  1371.  
  1372. void
  1373. printaddr(a, follow)
  1374.     register ADDRESS *a;
  1375.     bool follow;
  1376. {
  1377.     bool first = TRUE;
  1378.  
  1379.     while (a != NULL)
  1380.     {
  1381.         first = FALSE;
  1382.         printf("%x=", a);
  1383.         (void) fflush(stdout);
  1384.         printf("%s: mailer %d (%s), host `%s', user `%s', ruser `%s'\n",
  1385.                a->q_paddr, a->q_mailer->m_mno, a->q_mailer->m_name,
  1386.                a->q_host, a->q_user, a->q_ruser? a->q_ruser: "<null>");
  1387.         printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags,
  1388.                a->q_alias);
  1389.         printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home,
  1390.                a->q_fullname);
  1391.  
  1392.         if (!follow)
  1393.             return;
  1394.         a = a->q_next;
  1395.     }
  1396.     if (first)
  1397.         printf("[NULL]\n");
  1398. }
  1399.  
  1400. /*
  1401. **  REMOTENAME -- return the name relative to the current mailer
  1402. **
  1403. **    Parameters:
  1404. **        name -- the name to translate.
  1405. **        m -- the mailer that we want to do rewriting relative
  1406. **            to.
  1407. **        senderaddress -- if set, uses the sender rewriting rules
  1408. **            rather than the recipient rewriting rules.
  1409. **        canonical -- if set, strip out any comment information,
  1410. **            etc.
  1411. **        headeraddress -- if set, use header specific rewriting
  1412. **            rulesets and uurelativize if M_RELATIVIZE is set.
  1413. **
  1414. **    Returns:
  1415. **        the text string representing this address relative to
  1416. **            the receiving mailer.
  1417. **
  1418. **    Side Effects:
  1419. **        none.
  1420. **
  1421. **    Warnings:
  1422. **        The text string returned is tucked away locally;
  1423. **            copy it if you intend to save it.
  1424. */
  1425.  
  1426. char *
  1427. remotename(name, m, senderaddress, canonical, headeraddress)
  1428.     char *name;
  1429.     MAILER *m;
  1430.     bool senderaddress;
  1431.     bool canonical;
  1432.     bool headeraddress;
  1433. {
  1434.     register char **pvp;
  1435.     char *fancy;
  1436.     char *oldg = macvalue('g', CurEnv);
  1437.     static char buf[MAXNAME];
  1438.     char lbuf[MAXNAME];
  1439.     char pvpbuf[PSBUFSIZE];
  1440.  
  1441.     if (tTd(12, 1))
  1442.         printf("remotename(%s)\n", name);
  1443.  
  1444.     /* don't do anything if we are tagging it as special */
  1445.     if ((senderaddress ?
  1446.          (headeraddress ? m->m_sh_rwset : m->m_se_rwset) :
  1447.          (headeraddress ? m->m_rh_rwset : m->m_re_rwset)) < 0)
  1448.         return (name);
  1449.  
  1450.     /*
  1451.     **  Do a heuristic crack of this name to extract any comment info.
  1452.     **    This will leave the name as a comment and a $g macro.
  1453.     */
  1454.  
  1455.     if (canonical)
  1456.         fancy = "\001g";
  1457.     else
  1458.         fancy = crackaddr(name);
  1459.  
  1460.     /*
  1461.     **  Turn the name into canonical form.
  1462.     **    Normally this will be RFC 822 style, i.e., "user@domain".
  1463.     **    If this only resolves to "user", and the "C" flag is
  1464.     **    specified in the sending mailer, then the sender's
  1465.     **    domain will be appended.
  1466.     */
  1467.  
  1468.     pvp = prescan(name, '\0', pvpbuf);
  1469.     if (pvp == NULL)
  1470.         return (name);
  1471.     rewrite(pvp, 3);
  1472.     if (CurEnv->e_fromdomain != NULL)
  1473.     {
  1474.         /* append from domain to this address */
  1475.         register char **pxp = pvp;
  1476.  
  1477.         /* see if there is an "@domain" in the current name */
  1478.         while (*pxp != NULL && strcmp(*pxp, "@") != 0)
  1479.             pxp++;
  1480.         if (*pxp == NULL)
  1481.         {
  1482.             /* no.... append the "@domain" from the sender */
  1483.             register char **qxq = CurEnv->e_fromdomain;
  1484.  
  1485.             while ((*pxp++ = *qxq++) != NULL)
  1486.                 continue;
  1487.             rewrite(pvp, 3);
  1488.         }
  1489.     }
  1490.  
  1491.     /*
  1492.     **  Do more specific rewriting.
  1493.     **    Rewrite using ruleset 1 or 2 for envelope addresses and
  1494.     **    5 or 6 for header addresses depending on whether this
  1495.     **    is a sender address or not.
  1496.     **    Then run it through any receiving-mailer-specific rulesets.
  1497.     */
  1498.  
  1499.     if (senderaddress)
  1500.     {
  1501.         if (headeraddress)
  1502.         {
  1503.             rewrite(pvp, SplitRewriting ? 5 : 1);
  1504.             if (m->m_sh_rwset > 0)
  1505.                 rewrite(pvp, m->m_sh_rwset);
  1506.         }
  1507.         else
  1508.     {
  1509.         rewrite(pvp, 1);
  1510.             if (m->m_se_rwset > 0)
  1511.                 rewrite(pvp, m->m_se_rwset);
  1512.     }
  1513.     }
  1514.     else
  1515.     {
  1516.         if (headeraddress)
  1517.         {
  1518.             rewrite(pvp, SplitRewriting ? 6 : 2);
  1519.             if (m->m_rh_rwset > 0)
  1520.                 rewrite(pvp, m->m_rh_rwset);
  1521.         }
  1522.         else
  1523.         {
  1524.         rewrite(pvp, 2);
  1525.             if (m->m_re_rwset > 0)
  1526.                 rewrite(pvp, m->m_re_rwset);
  1527.     }
  1528.     }
  1529.  
  1530.     /*
  1531.     **  Do any final sanitation the address may require.
  1532.     **    This will normally be used to turn internal forms
  1533.     **    (e.g., user@host.LOCAL) into external form.  This
  1534.     **    may be used as a default to the above rules.
  1535.     */
  1536.  
  1537.     rewrite(pvp, 4);
  1538.  
  1539.     /*
  1540.     **  Check if we're supposed to do make the address
  1541.     **  UUCP !-relative to the rcpt host vs ourselves.
  1542.     */
  1543.  
  1544.     if (headeraddress && bitnset(M_RELATIVIZE, m->m_flags))
  1545.         uurelativize("\001k", "\001h", pvp);
  1546.  
  1547.     /*
  1548.     **  Now restore the comment information we had at the beginning.
  1549.     */
  1550.  
  1551.     cataddr(pvp, lbuf, sizeof lbuf);
  1552.     define('g', lbuf, CurEnv);
  1553.     expand(fancy, buf, &buf[sizeof buf - 1], CurEnv);
  1554.     define('g', oldg, CurEnv);
  1555.  
  1556.     if (tTd(12, 1))
  1557.         printf("remotename => `%s'\n", buf);
  1558.     return (buf);
  1559. }
  1560. /*
  1561. **  UURELATIVIZE -- Make an address !-relative to recipient/sender nodes
  1562. **
  1563. **    Parameters:
  1564. **        from -- the sending node (usually "$k" or "$w")
  1565. **        to -- the receiving node (usually "$h")
  1566. **        pvp -- address vector
  1567. **
  1568. **    Returns:
  1569. **        none.
  1570. **
  1571. **    Side Effects:
  1572. **        The pvp is rewritten to be relative the "to" node
  1573. **        wrt the "from" node.  In other words, if the pvp
  1574. **        is headed by "to!" that part is stripped; otherwise
  1575. **        "from!" is prepended.  Exception: "to!user" addresses
  1576. **        with no '!'s in the user part are sent as is.
  1577. **
  1578. **    Bugs:
  1579. **        The pvp may overflow, but we don't catch it.
  1580. */
  1581.  
  1582. static void
  1583. uurelativize(from, to, pvp)
  1584.     const char *from, *to;
  1585.     char **pvp;
  1586. {
  1587.     register char **pxp = pvp;
  1588.     char expfrom[MAXNAME], expto[MAXNAME];
  1589.  
  1590.     expand(from, expfrom, &expfrom[sizeof expfrom - 1], CurEnv);
  1591.     expand(to, expto, &expto[sizeof expto - 1], CurEnv);
  1592.  
  1593.     /*
  1594.      * supposing that we've got something, should
  1595.      * we add "from!" or remove "to!"?
  1596.      */
  1597.     if (pvp[0] != NULL)
  1598.         if (pvp[1] == NULL || strcmp(pvp[1], "!") != 0 ||
  1599.             /*strcasecmp?*/ strcmp(pvp[0], expto) != 0)
  1600.         {
  1601.             /* either local name, no UUCP address, */
  1602.             /* or not to "to!" ==> prepend address with "from!" */
  1603.  
  1604.             /* already there? */
  1605.             if (pvp[1] == NULL || strcmp(pvp[1], "!") != 0 ||
  1606.                 /*strcasecmp?*/ strcmp(pvp[0], expfrom) != 0)
  1607.             {
  1608.  
  1609.                 /* no, put it there */
  1610.                 while (*pxp != NULL)
  1611.                     pxp++;
  1612.                 do
  1613.                     pxp[2] = *pxp;
  1614.                 while (pxp-- != pvp);
  1615.                 pvp[0] = newstr(expfrom);
  1616.                 pvp[1] = "!";
  1617.             }
  1618.         }
  1619.         else
  1620.         {
  1621.             /* address is to "to!" -- remove if not "to!user" */
  1622.             for (pxp = &pvp[2];
  1623.                 *pxp != NULL && strcmp(*pxp, "!") != 0;
  1624.                 pxp++);
  1625.                 if (*pxp != NULL)
  1626.                     for (pxp = pvp; *pxp != NULL; pxp++)
  1627.                         *pxp = pxp[2];
  1628.         }
  1629. }
  1630.